package com.yb.framework.neo4j.repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Value;
import org.neo4j.driver.v1.types.Node;
import org.neo4j.driver.v1.types.Relationship;
import org.neo4j.driver.v1.util.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yb.framework.core.utils.StringUtil;
import com.yb.framework.neo4j.domain.NodeEntity;
import com.yb.framework.neo4j.utils.Neo4jUtil;

@Repository
public class Neo4jRepository {
	
	@Autowired
	private Neo4jUtil neo4jUtil;
	
	/**
	 * 创建节点（不用关联shape、template，对shape）
	 * @param label 标签
	 * @param nodeUuid 节点ID
	 * @param nodeName 节点名
	 */
	public void createNode(String label, String nodeUuid, String nodeName) {
		try {
			// 根据label和nodeUuid进行查找记录
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' return n", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(!statementResult.hasNext()) {
				// 无记录，新增
				NodeEntity nodeEntity = new NodeEntity(label, nodeUuid, nodeName);
				String propertiesJsonStr = neo4jUtil.getPropertiesJson(JSON.toJSONString(nodeEntity));
				String createNodeSql = String.format("create (n:`%s` %s) return n", label, propertiesJsonStr);
				neo4jUtil.excuteCypherSql(createNodeSql);
			} else {
				// 有记录，编辑
				String updateNodeSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
				neo4jUtil.excuteCypherSql(updateNodeSql);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建节点（可以关联shape、template，对template）
	 */
	public void createTemplateNode(String label, String nodeUuid, String nodeName, String parentNodeUuid, String... shapeNodeUuids) {
		try {
			// 根据label和nodeUuid进行查找记录
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' return n", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(!statementResult.hasNext()) {
				// 无记录，新增
				NodeEntity nodeEntity = new NodeEntity(label, nodeUuid, nodeName);
				String propertiesJsonStr = neo4jUtil.getPropertiesJson(JSON.toJSONString(nodeEntity));
				String createNodeSql = String.format("create (n:`%s` %s) return n", label, propertiesJsonStr);
				neo4jUtil.excuteCypherSql(createNodeSql);
			} else {
				// 有记录，编辑
				String updateNodeSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
				neo4jUtil.excuteCypherSql(updateNodeSql);
			}
			
			// 新建与Parent的关系
			if(StringUtil.isNotNull(parentNodeUuid)) {
				String createShipSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
						+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, label, nodeUuid, parentNodeUuid);
				neo4jUtil.excuteCypherSql(createShipSql);
			}
			
			// 新建与Shape的关系
			if(shapeNodeUuids != null && shapeNodeUuids.length > 0) {
				for (String shapeNodeUuid : shapeNodeUuids) {
					String createShipSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
							+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, "shape", nodeUuid, shapeNodeUuid);
					neo4jUtil.excuteCypherSql(createShipSql);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建节点（可以关联shape、template，对template和thing）
	 */
	public void createThingNode(String label, String nodeUuid, String nodeName, String tempalteNodeUuid, String... shapeNodeUuids) {
		try {
			// 根据label和nodeUuid进行查找记录
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' return n", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(!statementResult.hasNext()) {
				// 无记录，新增
				NodeEntity nodeEntity = new NodeEntity(label, nodeUuid, nodeName);
				String propertiesJsonStr = neo4jUtil.getPropertiesJson(JSON.toJSONString(nodeEntity));
				String createNodeSql = String.format("create (n:`%s` %s) return n", label, propertiesJsonStr);
				neo4jUtil.excuteCypherSql(createNodeSql);
			} else {
				// 有记录，编辑
				String updateNodeSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
				neo4jUtil.excuteCypherSql(updateNodeSql);
			}
			
			// 新建与Template的关系
			if(StringUtil.isNotNull(tempalteNodeUuid)) {
				String createRelationSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
						+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, "template", nodeUuid, tempalteNodeUuid);
				neo4jUtil.excuteCypherSql(createRelationSql);
			}
			
			// 新建与Shape的关系
			if(shapeNodeUuids != null && shapeNodeUuids.length > 0) {
				for (String shapeNodeUuid : shapeNodeUuids) {
					String createShapeRelationSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
							+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, "shape", nodeUuid, shapeNodeUuid);
					neo4jUtil.excuteCypherSql(createShapeRelationSql);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建节点（对属性进行创建节点，关联shape、template、thing）
	 */
	public void createParamNode(String label, String nodeUuid, String nodeName, String relationLabel, String relationUuid) {
		try {
			// 根据label和nodeUuid进行查找记录
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' return n", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(!statementResult.hasNext()) {
				// 无记录，新增
				NodeEntity nodeEntity = new NodeEntity(label, nodeUuid, nodeName);
				String propertiesJsonStr = neo4jUtil.getPropertiesJson(JSON.toJSONString(nodeEntity));
				String createNodeSql = String.format("create (n:`%s` %s) return n", label, propertiesJsonStr);
				neo4jUtil.excuteCypherSql(createNodeSql);
			} else {
				// 有记录，编辑
				String updateNodeSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
				neo4jUtil.excuteCypherSql(updateNodeSql);
			}
			
			// 建立关系
			if(StringUtil.isNotNull(relationUuid)) {
				String createShipSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
						+ "CREATE (n)-[r:R]->(m)" + "RETURN r", relationLabel, label, relationUuid, nodeUuid);
				neo4jUtil.excuteCypherSql(createShipSql);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新节点
	 */
	public void updateNode(String label, String nodeUuid, String nodeName) {
		try {
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
			neo4jUtil.excuteCypherSql(cypherSql);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新节点（更新关系）
	 */
	public void updateNode(String label, String nodeUuid, String nodeName, String relationLabel, String relationUuid) {
		try {
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
			neo4jUtil.excuteCypherSql(cypherSql);
			
			// 先删除
			String deleteRelationSql = String.format("MATCH (n:`%s`) <-[r:R]-> (m:`template`) where n.uuid = '%s' delete r", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteRelationSql);
			if(StringUtil.isNotNull(relationUuid)) {
				// 再创建
				String createRelationSql = String.format("MATCH (n:`%s`),(m:`%s`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
						+ "CREATE (n)-[r:R]->(m)" + "RETURN r", relationLabel, label, relationUuid, nodeUuid);
				neo4jUtil.excuteCypherSql(createRelationSql);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新节点（更新名称、关系）
	 */
	public void updateNode(String label, String nodeUuid, String nodeName, String tempalteNodeUuid, String... shapeNodeUuids) {
		try {
			// Node
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' set n.name='%s' return n", label, nodeUuid, nodeName);
			neo4jUtil.excuteCypherSql(cypherSql);
			
			// Thing Template
			// 先删除
			String deleteTempRelationSql = String.format("MATCH (n:`%s`) <-[r:R]-> (m:`template`) where n.uuid = '%s' delete r", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteTempRelationSql);
			if(StringUtil.isNotNull(tempalteNodeUuid)) {
				// 再创建
				String createRelationSql = String.format("MATCH (n:`%s`),(m:`template`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
						+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, nodeUuid, tempalteNodeUuid);
				neo4jUtil.excuteCypherSql(createRelationSql);
			}
			
			// Thing Shape
			// 先删除
			String deleteShapeRelationSql = String.format("MATCH (n:`%s`) <-[r:R]-> (m:`shape`) where n.uuid = '%s' delete r", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteShapeRelationSql);
			if(shapeNodeUuids != null && shapeNodeUuids.length > 0) {
				// 再创建
				for (String shapeNodeUuid : shapeNodeUuids) {
					String createShipSql = String.format("MATCH (n:`%s`),(m:`shape`) WHERE n.uuid = '%s' AND m.uuid = '%s' "
							+ "CREATE (n)-[r:R]->(m)" + "RETURN r", label, nodeUuid, shapeNodeUuid);
					neo4jUtil.excuteCypherSql(createShipSql);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除节点(先删除关系再删除节点)
	 */
	public void deleteNode(String label, String nodeUuid) {
		try {
			//删除与节点关联的参数节点
			String deleteParamSql = String.format("MATCH (n:`%s`) <-[r:R]->(m:`param`) where n.uuid = '%s' delete r,m", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteParamSql);
			//删除与节点关联的关系
			String deleteRelationSql = String.format("MATCH (n:`%s`) <-[r:R]->(m) where n.uuid = '%s' delete r", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteRelationSql);
			//删除节点
			String deleteNodeSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' delete n", label, nodeUuid);
			neo4jUtil.excuteCypherSql(deleteNodeSql);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除Neo4j标签
	 */
	public void deleteLabel(String label) {
		try {
			String rSql = String.format("MATCH (n:`%s`) -[r:R] - (m)  delete r", label);
			neo4jUtil.excuteCypherSql(rSql);
			String deleteNodeSql = String.format("MATCH (n:`%s`) delete n", label);
			neo4jUtil.excuteCypherSql(deleteNodeSql);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 获取节点信息
	public JSONObject getNode(String label, String nodeUuid) {
		JSONObject result = new JSONObject();
		try {
			String cypherSql = String.format("MATCH (n:`%s`) where n.uuid = '%s' return n", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(statementResult.hasNext()) {
				
				JSONArray nodeList = new JSONArray();
				
				List<Record> recordList = statementResult.list();
				for (Record record : recordList) {
					List<Pair<String, Value>> fields = record.fields();
					for (Pair<String, Value> field : fields) {
						String typeName = field.value().type().name();
						if (typeName.equals("NODE")) {
							JSONObject nodeMap = new JSONObject();
							Node node = field.value().asNode();
							nodeMap.put("nodeId", node.id());
							// 添加节点属性
							Map<String, Object> nodeAsMap = node.asMap();
							for (Entry<String, Object> nodeEntry : nodeAsMap.entrySet()) {
								String key = nodeEntry.getKey();
								Object value = nodeEntry.getValue();
								nodeMap.put(key, value);
							}
                            if (nodeMap != null && !nodeMap.isEmpty()) {
                            	nodeMap.put("symbolSize", 60);
                            	nodeList.add(nodeMap);
                            }
						}
					}
				}
				result.put("nodeList", nodeList);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	
	// 获取子节点信息
	public JSONObject getChildNodes(String label, String nodeUuid) {
		JSONObject result = new JSONObject();
		try {
			String cypherSql = String.format("MATCH (n:`%s`) -[r:R] -> (m) where n.uuid = '%s' return r, m limit 100", label, nodeUuid);
			StatementResult statementResult = neo4jUtil.excuteCypherSql(cypherSql);
			if(statementResult.hasNext()) {
				
				// 结果参数
				JSONArray nodeList = new JSONArray();
				JSONArray shipList = new JSONArray();
				// 用于判断查找重复的情况
				JSONArray nodeIds = new JSONArray(); 
				JSONArray shipIds = new JSONArray();
				
				List<Record> recordList = statementResult.list();
				for (Record record : recordList) {
					List<Pair<String, Value>> fields = record.fields();
					for (Pair<String, Value> field : fields) {
						String typeName = field.value().type().name();
						// 类型为节点
						if (typeName.equals("NODE")) {
							JSONObject nodeMap = new JSONObject();
							Node node = field.value().asNode();
							if(!nodeIds.contains(String.valueOf(node.id()))) {
								nodeIds.add(node.id());
								nodeMap.put("nodeId", node.id());
								// 添加节点属性
								Map<String, Object> nodeAsMap = node.asMap();
								for (Entry<String, Object> nodeEntry : nodeAsMap.entrySet()) {
									String key = nodeEntry.getKey();
									Object value = nodeEntry.getValue();
									nodeMap.put(key, value);
								}
							}
                            if (nodeMap != null && !nodeMap.isEmpty()) {
                            	if("param".equals(nodeMap.getString("label"))) {
                                	nodeMap.put("symbolSize", 30);
                            	} else {
                                	nodeMap.put("symbolSize", 40);
                            	}
                            	nodeList.add(nodeMap);
                            }
						}
						// 类型为关系
						else if (typeName.equals("RELATIONSHIP")) {
							HashMap<String, Object> shipMap = new HashMap<String, Object>();
							Relationship relationship = field.value().asRelationship();
							if(!shipIds.contains(relationship.id())) {
								shipIds.add(relationship.id());
								shipMap.put("shipId", relationship.id());
								shipMap.put("startNodeId", relationship.startNodeId());
								shipMap.put("endNodeId", relationship.endNodeId());
								// 添加关系属性
								Map<String, Object> relationshipAsMap = relationship.asMap();
								for (Entry<String, Object> relationshipEntry : relationshipAsMap.entrySet()) {
									String key = relationshipEntry.getKey();
									Object value = relationshipEntry.getValue();
									shipMap.put(key, value);
								}
							}
                            if (shipMap != null && !shipMap.isEmpty()) {
                                shipList.add(shipMap);
                            }
						}
					}
				}
				result.put("nodeNum", nodeIds.size());
				result.put("nodeList", nodeList);
				result.put("shipNum", shipIds.size());
				result.put("shipList", shipList);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	
	// 递归获取所有子节点信息
	public JSONObject getAllChildNodes(JSONObject childNodes, JSONObject allChildNodes) {
		if(childNodes != null && !childNodes.isEmpty() && childNodes.getIntValue("nodeNum") > 0) {
			
			JSONArray nodeList = new JSONArray();
			JSONArray shipList = new JSONArray();
			
			if(allChildNodes != null && allChildNodes.getJSONArray("nodeList") != null && allChildNodes.getJSONArray("nodeList").size() > 0) {
				nodeList = allChildNodes.getJSONArray("nodeList");
			}
			if(allChildNodes != null && allChildNodes.getJSONArray("shipList") != null && allChildNodes.getJSONArray("shipList").size() > 0) {
				shipList = allChildNodes.getJSONArray("shipList");
			}
			nodeList.addAll(childNodes.getJSONArray("nodeList"));
			shipList.addAll(childNodes.getJSONArray("shipList"));
			allChildNodes.put("nodeList", nodeList);
			allChildNodes.put("shipList", shipList);
			
			for (int i = 0; i < childNodes.getIntValue("nodeNum"); i++) {
				JSONObject nodeObj = childNodes.getJSONArray("nodeList").getJSONObject(i);
				JSONObject childNodesObj = getChildNodes(nodeObj.getString("label"), nodeObj.getString("uuid"));
				if(childNodesObj != null && childNodesObj.getIntValue("nodeNum") > 0) {
					allChildNodes = getAllChildNodes(childNodesObj, allChildNodes);
				}
			}
		}
		return allChildNodes;
	}
}
